/**
 * 
 */
package hyl.base.net.ftp;

import org.apache.commons.net.ftp.FTPReply;

import com.jcraft.jsch.SftpException;

import hyl.core.Amy;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;

/**
 * @author 邹达有
 * @mail 37798955@qq.com
 * 
 *       2022年7月28日
 * 
 */
public class Ftp implements IFtp {
	private FTPClient client = null;
	/** SFTP 登录用户名 */
	private String username;
	/** SFTP 登录密码 */
	private String password;
	/** SFTP 服务器地址IP地址 */
	private String host;
	/** SFTP 端口 */
	private int port;
	public Ftp(String username, String password, String host, int port) {
		this.username = username;
		this.password = password;
		this.host = host;
		this.port = port;
	}

	public void do登录() {
		if (this.client == null) {
			client = new FTPClient();
			try {
				client.connect(host, port);
				client.login(username, password);
				int reply = client.getReplyCode();
				if (!FTPReply.isPositiveCompletion(reply)) {
					client.disconnect();
					System.err.println("FTP  服务器 拒绝连接");
					return;
				}
				Amy.Log.info("成功连接 ftp 服务器");
			} catch (IOException e) {
				Amy.Log.error("连接 ftp 服务器失败 ! 原因: " + e.getMessage());

			}
		}
	}

	public void do断开连接() {
		if (client != null && client.isConnected()) {
			try {
				// 退出登录
				client.logout();
				// 断开连接
				client.disconnect();
				System.out.println("退出登录，断开连接");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public void do上传( String 上传到Ftp文件目录, String 上传后Ftp文件名,InputStream 上传本地文件流) {

		if (client == null) {
			return;
		}

		// 文件上传的ftp服务器目录
		String ftpPath = 上传到Ftp文件目录;
		// 将目录名称转为iso-8859-1编码 (FTP协议里面，规定文件名编码为iso-8859-1)
		String validPath = new String(ftpPath.getBytes(), StandardCharsets.ISO_8859_1);

		// 文件上传到ftp的文件名
		String fileName = 上传后Ftp文件名;
		// FTP协议里面，规定文件名编码为iso-8859-1
		String ftpFileName = new String(fileName.getBytes(), StandardCharsets.ISO_8859_1);

		try {

			// 设置缓冲区大小
			client.setBufferSize(4 * 1024 * 1024);
			// 设置编码
			// ftpClient.setControlEncoding("utf-8");
			// 设置模式很重要
			//client.enterLocalActiveMode();
			client.enterLocalPassiveMode();
			// 设置上传文件的类型为二进制类型
			client.setFileType(FTP.BINARY_FILE_TYPE);
			boolean changeWorkDirFlag = client.changeWorkingDirectory(validPath);
			if (!changeWorkDirFlag) {
				创建目录(client, validPath);
			}

			// 存储文件至ftp服务器
			boolean result = client.storeFile(ftpFileName, 上传本地文件流);
			上传本地文件流.close();
			Amy.Log.error("上传文件" + (result ? "成功" : "失败"));

		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	static void 创建目录(FTPClient ftpClient, String directory) {

		String fileSeparator = "/";
		if (!directory.endsWith(fileSeparator)) {
			directory += fileSeparator;
		}
		int fromIndex = 0;
		int endIndex = 0;
		try {
			if (ftpClient.changeWorkingDirectory(directory)) {
				// 如果目录存在，直接返回
				return;
			}
			if (directory.startsWith(fileSeparator)) {
				fromIndex = 1;
			}
			endIndex = directory.indexOf(fileSeparator, fromIndex);
			while (true) {
				String subDirectory = new String(directory.substring(fromIndex, endIndex));
				if (!ftpClient.changeWorkingDirectory(subDirectory)) {
					if (ftpClient.makeDirectory(subDirectory)) {
						ftpClient.changeWorkingDirectory(subDirectory);
					} else {
						System.out.println("创建" + subDirectory + "目录失败");
						return;
					}
				}
				fromIndex = endIndex + 1;
				endIndex = directory.indexOf(fileSeparator, fromIndex);
				// 检查所有目录是否创建完毕
				if (endIndex <= fromIndex) {
					break;
				}
			}
			System.out.println("上传目录创建成功");
		} catch (Exception e) {
			System.out.println("上传目录创建失败");
			e.printStackTrace();
		}
	}

	/**
	 * 下载文件
	 */
	public void do下载(String ftp文件目录,String ftp文件名,  String 本地文件存储路径) {
		String ftp文件路径=ftp文件目录+File.separatorChar+ftp文件名;
		// ftp服务器文件名
		String validFtpFilePath = new String(ftp文件路径.getBytes(), StandardCharsets.ISO_8859_1);
		// 下载到本地地址
		try {
			OutputStream os = new FileOutputStream(本地文件存储路径);
			// 1、检查文件是否存在
			if (!is存在(ftp文件路径)) {
				System.out.println("文件不存在");
			} else {
				boolean flag = client.retrieveFile(validFtpFilePath, os);
				System.out.println("下载文件" + (flag ? "成功" : "失败"));
			}
		} catch (Exception e) {
			e.printStackTrace();
		} 
	}

	/**
	 * 判断文件是否存在
	 * 
	 * @param ftpFile
	 * @param ftpClient
	 * @return
	 */
	public boolean is存在(String ftpFile) {
		if (client != null) {
			try {
				String validFtpFile = new String(ftpFile.getBytes(), StandardCharsets.ISO_8859_1);
				String path = validFtpFile.substring(0, validFtpFile.lastIndexOf("/"));
				String fileName = validFtpFile.substring(validFtpFile.lastIndexOf("/") + 1);
				// 判断是否存在该目录
				boolean changeWorkDirFlag = client.changeWorkingDirectory(path);
				if (!changeWorkDirFlag) {
					System.out.println("目录不存在");
					return false;
				}
				client.enterLocalPassiveMode(); // 设置被动模式，开通一个端口来传输数据
				String[] fs = client.listNames();
				// 判断该目录下是否有文件
				if (fs == null || fs.length == 0) {
					System.out.println("该目录下没有文件");
					return false;
				}
				for (String ftpName : fs) {
					if (ftpName.equals(fileName)) {
						return true;
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return false;
	}

	/**
	 * 删除文件
	 */
	public void do删除Ftp端文件(String ftp文件目录,String ftp文件名) {
		String ftp文件路径=ftp文件目录+File.separatorChar+ftp文件名;
		String fileName = ftp文件路径;
		String validFileName = new String(fileName.getBytes(), StandardCharsets.ISO_8859_1);
		boolean flag;
		try {
			flag = client.deleteFile(validFileName);
			System.out.println("文件删除结果:" + flag);
		} catch (IOException e) {
			e.printStackTrace();
		}
		}

	/**
	 * 写文件
	 */
	public void do写入到服务端( String 写入到Ftp文件,InputStream 写入内容) {
		String validFileName = new String(写入到Ftp文件.getBytes(), StandardCharsets.ISO_8859_1);
		// 将content转为输入流
		// ByteArrayInputStream is = new ByteArrayInputStream(写入内容);
		try {
			boolean flag = client.storeFile(validFileName, 写入内容);
			System.out.println("写文件至ftp" + (flag ? "成功" : "失败"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 读文件
	 */
	public InputStream do从服务端读取(String Ftp文件路径) {

		String validFileName = new String(Ftp文件路径.getBytes(), StandardCharsets.ISO_8859_1);
		try {
			if (!is存在(Ftp文件路径)) {
				System.out.println("文件不存在");
				return null;
			}
			InputStream inputStream = client.retrieveFileStream(validFileName);
			return inputStream;

		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;

	}
	public static void demo() throws SftpException, IOException {
		Ftp ftp = new Ftp("root", "root", "ip", 22);
		ftp.do登录();
		System.out.println(ftp.client.isConnected());
		System.out.println(ftp.client.getStatus());
		for (int i = 0; i < 5; i++) {
			File file = new File("D:\\uploadFile\\ftp.txt");
			InputStream is = new FileInputStream(file);
			ftp.do上传("/root/nginx/uploadFile", System.currentTimeMillis() + ".txt", is);
			
		}
		ftp.do下载("/root/nginx/uploadFile/","001.txt", "D:\\downfile\\test.txt");
		ftp.do断开连接();

	}
}
